//InterfaceAgent.scala
package mycore

import chisel3._
import chisel3.util._

class InterfaceAgent extends Module {
  val io = IO(new Bundle {

    val TIME = Input(Bool())

  	val ramhelperIO = new RAMHelperIO
    val mycoreIO = new MyCoreIO

    val isSoC = Input(Bool())
  })

  /*
      TIME = 0  -> 时间暂停 
                -> 所有寄存器停止变化：ENABLE/INST/StateReg
                -> 关键信号置0：io.mycoreIO.ENABLE                  
  */


  val ENABLE = RegInit(false.B)
  val INST   = RegInit(0.U(32.W))
  val Inst32 = Mux(io.mycoreIO.InstFetch.addr(2).asBool(), io.ramhelperIO.rdata(63,32), io.ramhelperIO.rdata(31,0))

  io.mycoreIO.ENABLE          := Mux(io.TIME, ENABLE, false.B)
  io.mycoreIO.InstFetch.data  := INST
  io.mycoreIO.DataLoad.data   := io.ramhelperIO.rdata

  /*--------------------------
      Finite-State Machine
  ---------------------------*/
  val inst :: memory :: Nil = Enum(2)
  val StateReg = RegInit(inst)

  switch(StateReg){
    is(inst){

      when(io.TIME){
        StateReg  := memory
        ENABLE    := true.B
        INST      := Inst32
      }
      
    }
    is(memory){

      when(io.TIME){
        StateReg  := inst
        ENABLE    := false.B
        INST      := 0x13.U
      }
      
    }
  }

  val IF_size = Mux(io.isSoC, 2.U, 3.U)
  val addr_offset = Mux(io.isSoC, "h0000000000000000".U(64.W), "h0000000080000000".U(64.W))

  val fetch_addr  = io.mycoreIO.InstFetch.addr - addr_offset
  val load_addr   = io.mycoreIO.DataLoad.addr - addr_offset
  val store_addr  = io.mycoreIO.DataStore.addr - addr_offset

  val memory_en = io.mycoreIO.DataLoad.en || io.mycoreIO.DataStore.en

  io.ramhelperIO.clk    := clock
  io.ramhelperIO.en     := ((StateReg===inst) || (StateReg===memory && memory_en))
  io.ramhelperIO.rIdx   := Mux(StateReg===inst, fetch_addr, load_addr)
  io.ramhelperIO.rsize  := Mux(StateReg===memory && io.mycoreIO.DataLoad.en, io.mycoreIO.DataLoad.size, IF_size)
  io.ramhelperIO.wIdx   := store_addr
  io.ramhelperIO.wdata  := io.mycoreIO.DataStore.data
  io.ramhelperIO.wmask  := io.mycoreIO.DataStore.mask
  io.ramhelperIO.wen    := StateReg===memory && io.mycoreIO.DataStore.en

}

class RAMHelperIO extends Bundle{
  val clk = Output(Clock())
  val en = Output(Bool())
  val rIdx = Output(UInt(64.W))
  val rsize = Output(UInt(3.W)) //for axi
  val rdata = Input(UInt(64.W))
  val wIdx = Output(UInt(64.W))
  val wdata = Output(UInt(64.W))
  val wmask = Output(UInt(8.W))
  val wen = Output(Bool())
}

class MyCoreIO extends Bundle{
  val ENABLE = Output(Bool())
  val InstFetch = Flipped(new InstFetch)
  val DataLoad = Flipped(new DataLoad)
  val DataStore = Flipped(new DataStore)
}